
package com.hlkj.pay.app.merchant.ext.impl.wxpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.ijpay.core.kit.WxPayKit;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.wxpay.WxScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.wxpay.constant.WxPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.wxpay.dto.WxAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.wxpay.dto.WxPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.wxpay.handler.WxPayCommonParamsHandle;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.AuthTypeEnum;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
import com.ijpay.wxpay.model.v3.*;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jodd.util.StringPool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * H5统一下单
 * 
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = WxPayExtConstant.H5)
public class WxH5PayOrderExtPt extends WxSceneCommonPayOrder implements WxScenePayOrderExtPt {

    private final WxPayCommonParamsHandle wxPayCommonParamsHandle;

    @Value("${hlkj.domain}")
    private String domain;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {

        log.info("微信H5支付开始请求参数:{}", JsonUtils.toJsonString(channelPayOrderContext));
        // 判断商户类型
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
        boolean common = false;
        if(merchantAppChannelDO.getType() != null && MerchantEnum.APP_CHANNEL_TYPE.MERCHANT_COMMON.getCode()  == merchantAppChannelDO.getType()){
            common = true;
        }
        // 微信配置信息
        WxPayConfig wxPayConfig = null;
        // 普通商户
        if(common){
            wxPayConfig = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), WxPayConfig.class);
            if(wxPayConfig == null){
                channelPayOrderContext.setRemark("普通商户未配置通道参数");
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
        }else{
            CommonResult<WxPayConfig> wxPayConfigCommonResult = wxPayCommonParamsHandle.wxPayConfig(channelPayOrderContext.getProviderChannelConfigDO(),
                    channelPayOrderContext.isTest());
            if (!wxPayConfigCommonResult.isSuccess()) {
                channelPayOrderContext.setRemark(wxPayConfigCommonResult.getMsg());
                channelPayOrderContext.setProcessStatus(false);
                return;
            }
            wxPayConfig = wxPayConfigCommonResult.getData();
        }

        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        // 额外参数信息
        PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();

        try {
            // 请求地址
            String url = null;
            // 请求参数封装
            UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel()
                    .setDescription(payOrderDO.getDescription())
                    .setOut_trade_no(payOrderDO.getPayOrderNo())
                    .setSettle_info(new SettleInfo().setProfit_sharing(true))
                    .setAmount(new Amount().setTotal(MerchantUtils.YuanToFen(payOrderDO.getAmount())).setCurrency("CNY"))
                    .setScene_info(
                            new SceneInfo()
                                    .setPayer_client_ip(payOrderDO.getClientIp())
                                    .setH5_info(new H5Info()
                                            .setType("Wap")
                                            .setApp_name(StringUtils.hasText(extra.getAppName()) ? extra.getAppName() : "")));

            // 普通商户
            if(common){
                // appid
                String appid = StrUtil.isNotEmpty(wxPayConfig.getWxMiniAppid()) ? wxPayConfig.getWxMiniAppid():wxPayConfig.getWxPubAppid();
                // 商户回调通知
                String notifyUrl = domain + MerchantExtConstant.MERCHANT_TRANS_COMMON_ASYNC_CALLBACK_URL + payOrderDO.getChannelCode() + StringPool.SLASH + payOrderDO.getProviderCode()+ StringPool.SLASH + merchantAppChannelDO.getCode();
                unifiedOrderModel.setAppid(appid).setMchid(wxPayConfig.getMchId()).setNotify_url(notifyUrl);
                url = BasePayApiEnum.H5_PAY.toString();
                log.info("普通商户微信H5支付请求参数:{}", JSONUtil.toJsonStr(unifiedOrderModel));
            }else{
                // 服务商
                WxAppChannelParams WxAppChannelParams = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), WxAppChannelParams.class);
                unifiedOrderModel.setSp_appid(extra.getSubAppid()).setSp_mchid(wxPayConfig.getMchId()).setSub_mchid(WxAppChannelParams.getSubMchId()).setNotify_url(channelPayOrderContext.getNotifyUrl());
                url = BasePayApiEnum.PARTNER_H5_PAY.toString();

                // 分账  优先接口传值没有就去配置取
                if(payOrderDO.getFundProcessType() != null && payOrderDO.getFundProcessType() != 0){
                    unifiedOrderModel.setSettle_info(new SettleInfo().setProfit_sharing(true));
                }else{
                    if(merchantAppChannelDO.getFundProcessType() != null && payOrderDO.getFundProcessType() != 0){
                        unifiedOrderModel.setSettle_info(new SettleInfo().setProfit_sharing(true));
                    }
                }
                log.info("服务商微信H5支付请求参数:{}", JSONUtil.toJsonStr(unifiedOrderModel));
            }

            // 响应参数
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    url,
                    wxPayConfig.getMchId(),
                    wxPayConfig.getSerialNo(),
                    wxPayConfig.getPayPublicId(),
                    wxPayConfig.getPrivateKeyPath(),
                    JSONUtil.toJsonStr(unifiedOrderModel),
                    AuthTypeEnum.RSA.getCode()
            );
            log.info("微信H5支付返回参数:{}", response);

            if (response.getStatus() == WxPayExtConstant.OK) {
                // 根据支付公钥来验证签名结果
                boolean verifySignature = WxPayKit.verifyPublicKeySignature(response, wxPayConfig.getPayPublicPath());
                if(!verifySignature){
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    channelPayOrderContext.setRemark("微信支付公钥验签失败");
                    return;
                }
                JSONObject resp = JSONUtil.parseObj(response.getBody());
                channelPayOrderContext.setPayDataType("pay_url");
                channelPayOrderContext.setPayInfo(resp.getStr("h5_url"));
            }else{
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                channelPayOrderContext.setRemark(response.getBody());
            }

        }catch (Exception e) {
            log.error("微信支付提交H5支付请求失败 message:{}",  e);
            channelPayOrderContext.setRemark("微信支付提交H5支付请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
